import "reflect-metadata";
import MetaHandle from "./meta-handle";
import instanceHandle from "./instance-handle";
import Container from "./container";

/**
 * 注入
 *
 * `@Inject()`
 * `attr!:Target`
 */
export function Inject() {
  return (prototype: Object, prototypeKey: string) => {
    MetaHandle.setInjection(prototype.constructor as Constructor, {
      attr: prototypeKey,
      target: Reflect.getMetadata("design:type", prototype, prototypeKey),
    });
  };
}

/**
 * 用与防止循环注入
 *
 * `@InjectRef(ref:()=>Target)`
 * `attr!:Target`
 */
export function InjectRef(ref: () => any) {
  return (prototype: Object, prototypeKey: string) => {
    MetaHandle.setInjection(prototype.constructor as Constructor, {
      attr: prototypeKey,
      ref,
    });
  };
}

/**
 * 标记当前容器为可初始化
 * containerKey:需要单例注入时，将共享单例注入的容器标记一个共同的key
 * `@Service(containerKey?:string)`
 * `class Target {}`
 */
export function Service(params?: ServiceTypes) {
  return <T extends Constructor>(target: T) => {
    let { key } = params || {};
    return class NewTarget extends target {
      static isService: boolean = true; //是否被标记
      static first_Instance: boolean = false; //是否被第一次实例化
      constructor(...args: any[]) {
        super(...args);
        if (!NewTarget.first_Instance) {
          let data = instanceHandle.Init(this, target.prototype);
          if (key) {
            data.bindContainer(Container.factory(key, true));
          }

          NewTarget.first_Instance = true;
        }
      }
    };
  };
}

/**
 * 将全部标记容器进行初始化
 *
 * `@Root()`
 * `class Target {}`
 */
export function Root() {
  return <T extends Constructor>(target: T) => {
    return class NewTarget extends target {
      static isRoot: boolean = false; //是否已被初始化
      constructor(...args: any[]) {
        super(...args);
        if (!NewTarget.isRoot) {
          NewTarget.isRoot = true;
          instanceHandle.factory(this)?.init();
        }
      }
    };
  };
}

/**
 * 调用被此装饰器装饰的方法时，销毁该容器的注入
 *
 * `@Destroy()`
 * `function(){}`
 */
export function Destroy() {
  return (
    prtotype: Object,
    prtotypeKey: string,
    descriptor: PropertyDescriptor
  ) => {
    let oldMethod = descriptor.value as Function;

    descriptor.value = function (...args: any[]) {
      if (instanceHandle.factory(this)?.haveDestroy) {
        throw new Error("该容器已销毁过");
      } else {
        oldMethod.apply(this, args);
        instanceHandle.factory(this)?.destroy();
      }
    };
  };
}

/**
 * 调用被此装饰器装饰的方法时，该方法被标记为容器初始化后才会执行
 *
 * `@Already()`
 * `function(){}`
 */
export function Already() {
  return (
    prtotype: Object,
    prtotypeKey: string,
    descriptor: PropertyDescriptor
  ) => {
    let methods = descriptor.value as Function;
    descriptor.value = function (...args: any[]) {
      instanceHandle.factory(this, prtotype, true).alreadyFn(() => {
        methods.apply(this, args);
      });
    };
  };
}
